package com.pf.utils;

import com.google.common.collect.Lists;
import com.pf.dto.OrderDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author PanFei
 * @version 1.0.0
 * @createTime 2021/9/8
 */
@Slf4j
public class SignUtils {

    public static void main(String[] args) throws Exception {
        // 服务端为客户端提供的唯一标识的固定值
        String appId = "pay_1234";
        String appSecret = "abc123";
        String token = "123456789";
        Map<String, String> reqParams = new HashMap<>();
        reqParams.put("appId", appId);
        reqParams.put("requestId", UUID.randomUUID().toString());
        reqParams.put("timestamp", System.currentTimeMillis() + "");

        OrderDTO subOrder1 = OrderDTO.builder().orderId("1001").orderName("子订单1").type(2).totalPrice(new BigDecimal("10")).build();
        OrderDTO subOrder2 = OrderDTO.builder().orderId("1002").orderName("子订单2").type(2).totalPrice(new BigDecimal("20")).build();
        List<OrderDTO> subOrders = Lists.newArrayList(subOrder1, subOrder2);
        OrderDTO parentOrder = OrderDTO.builder().orderId("1").orderName("父订单").type(1).totalPrice(new BigDecimal("30")).build();
        parentOrder.setSubOrders(subOrders);

        String sign = sign(appSecret, reqParams, parentOrder);
        log.info("sign=" + sign);

    }

    /**
     * 生成签名
     *
     * @param appSecret 服务端为客户端提供的唯一标识的密码固定值
     * @param reqParams 请求接口url后面拼接的参数，如 appId，requestId，timestamp，sign
     * @param reqBody   业务参数，如reqBody中的json数据
     * @return
     * @throws Exception
     */
    public static String sign(String appSecret, Map<String, String> reqParams, Object reqBody) throws Exception {
        // 为reqParams的key排序
        List<String> keys = reqParams.keySet().stream().filter(key -> !"sign".equals(key)).sorted().collect(Collectors.toList());

        // 将reqParams参数名和值拼接在一起
        StringBuilder reqParamStr = new StringBuilder();
        reqParamStr.append(appSecret);
        for (String key : keys) {
            String value = reqParams.get(key);
            if (StringUtils.isNoneBlank(key, value)) {
                reqParamStr.append(key).append(reqParams.get(key));
            }
        }
        String reqBodyStr = reqBody instanceof String ? (String) reqBody : JacksonUtils.toJsonString(reqBody);
        if (StringUtils.isNotBlank(reqBodyStr)) {
            reqParamStr.append(reqBodyStr);
        }
        // 使用MD5加密
        byte[] bytes;
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException ignored) {
            throw new Exception(ignored);
        }
        bytes = md5.digest(reqParamStr.toString().getBytes("UTF-8"));
        // 第四步：把二进制转化为大写的十六进制
        StringBuilder sign = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(b & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }

}
